﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using SynoManager.FileStation.Tasks;

namespace SynoManager.FileStation.Gui
{
    public partial class FileStationTab : UserControl
    {
        private readonly FileStationGuiPlugin plugin;
        private readonly FileStationService service;

        public FileStationTab()
        {
            InitializeComponent();
            this.Text = "Files";
        }

        public FileStationTab(FileStationGuiPlugin plugin)
            : this()
        {
            this.plugin = plugin;
            this.service = plugin.Service;
            taskQueueList.TaskQueue = service.TaskQueue;
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            LoadFolderIcons();
            LoadRoot();
        }

        private void LoadRoot()
        {
            treeView.Nodes.Clear();
            DeviceRoot root = service.GetRoot();
            treeView.Nodes.Add("/", service.Device.Address).Tag = root;
            LoadDirectory(root);
        }

        private DirectoryInfo queuedDirectory;
        private DirectoryInfo currentDirectory;
        private VolumeInfo volumeInfo;

        private void ReloadDirectory()
        {
            LoadDirectory(currentDirectory);
        }

        private void LoadDirectory(DirectoryInfo directory)
        {
            if (backgroundWorker.IsBusy)
            {
                queuedDirectory = directory;
                return;
            }

            queuedDirectory = null;
            toolStripProgressBar.Visible = true;
            listView.Items.Clear();

            //backgroundWorker_RunWorkerCompleted(null, new RunWorkerCompletedEventArgs(directory, null, false));
            backgroundWorker.RunWorkerAsync(directory);
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            DirectoryInfo directory = (DirectoryInfo)e.Argument;

            if (directory == currentDirectory)
                directory.Reload();    

            currentDirectory = directory;

            directory.GetDirectories();
            directory.GetFiles();

            if (directory.Path == "/")
                volumeInfo = null;
            else
                volumeInfo = service.GetVolumeInfo(directory.RelativePath);

            e.Result = directory;
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            DirectoryInfo directory = (DirectoryInfo) e.Result;
            if (directory == null)
            {
                toolStripProgressBar.Visible = false;
                return;
            }

            // update toolstrip
            updateListToolStrip();

            if (volumeInfo == null)
                volumeInfoToolStripStatusLabel.Text = String.Empty;
            else
                volumeInfoToolStripStatusLabel.Text = volumeInfo.ToString();

            var nodes = treeView.Nodes.Find(directory.Path, true);
            Debug.Assert(nodes.Length == 1, "Could not locate directory '" + directory.Path + "' in the tree.");
            TreeNode node = nodes[0];
            bool updateNodes = (node.Nodes.Count == 0);
            foreach (DirectoryInfo dir in directory.GetDirectories())
            {
                if (updateNodes)
                    node.Nodes.Add(dir.Path, dir.Name, closedFolderIconKey, openFolderIconKey).Tag = dir;

                ListViewItem lvi = listView.Items.Add(dir.Path, dir.Name, closedFolderIconKey);
                lvi.SubItems.Add("<Folder>");
                lvi.SubItems.Add("");
                lvi.SubItems.Add("");
                lvi.Tag = dir;
            }
            node.Expand();

            foreach (FileInfo file in directory.GetFiles())
            {
                string imageKey;
                string filename = file.Name;
                int index = filename.IndexOf('.');
                if (index > 0)
                    imageKey = filename.Substring(index);
                else
                    imageKey = filename;

                LoadFileIcon(imageKey);

                ListViewItem lvi = listView.Items.Add(file.Path, file.Name, imageKey);
                lvi.SubItems.Add(imageKey);
                lvi.SubItems.Add(file.Size.ToByteString());
                lvi.SubItems.Add(file.PermissionString);
                lvi.SubItems.Add(file.LastModified);
                lvi.SubItems.Add(file.Owner);
                lvi.Tag = file;
            }
            listView_SelectedIndexChanged(null, null);
            toolStripProgressBar.Visible = false;

            if (queuedDirectory != null)
                LoadDirectory(queuedDirectory);
        }

        private void updateListToolStrip()
        {
            bool isDeviceRoot = currentDirectory is DeviceRoot;
            
            parentFolderToolStripButton.Enabled = !isDeviceRoot;
            createFolderToolStripButton.Enabled = createFolderToolStripMenuItem.Enabled = !isDeviceRoot;

            downloadToolStripButton.Enabled =
                downloadToolStripMenuItem.Enabled = (!isDeviceRoot) && (listView.SelectedItems.Count > 0);
            uploadToolStripButton.Enabled = uploadToolStripMenuItem.Enabled = !isDeviceRoot;

            bool extractable = listView.SelectedItems.Count > 0;
            foreach(ListViewItem lvi in listView.SelectedItems)
            {
                FileInfo fileInfo = lvi.Tag as FileInfo;
                if (fileInfo == null)
                    extractable = false;
                else
                    extractable = fileInfo.IsExtractable;

                if (!extractable)
                    break;
            }
            extractToolStripButton.Enabled = extractToolStripMenuItem.Enabled = extractable;

            copyToolStripButton.Enabled = copyToolStripMenuItem.Enabled = (!isDeviceRoot) && (listView.SelectedItems.Count > 0);
            moveToolStripMenuItem.Enabled = moveToolStripButton.Enabled = (!isDeviceRoot) && (listView.SelectedItems.Count > 0);
            deleteToolStripButton.Enabled = deleteToolStripMenuItem.Enabled = (!isDeviceRoot) && (listView.SelectedItems.Count > 0);

            renameToolStripButton.Enabled = renameToolStripMenuItem.Enabled = (!isDeviceRoot) && (listView.SelectedItems.Count == 1);
            propertiesToolStripButton.Enabled = propertiesToolStripMenuItem.Enabled = (!isDeviceRoot) && (listView.SelectedItems.Count == 1);
        }

        #region Images / Icons
        private const string openFolderIconKey = "$OPENFOLDER$";
        private const string closedFolderIconKey = "$CLOSEDFOLDER$";
        private Icon defaultIconSmall;
        private Icon defaultIconLarge;

        private void LoadFolderIcons()
        {
            imageListSmall.Images.Add(openFolderIconKey, IconHelper.GetFolderIcon(IconHelper.IconSize.Small, IconHelper.FolderType.Open));
            imageListSmall.Images.Add(closedFolderIconKey, IconHelper.GetFolderIcon(IconHelper.IconSize.Small, IconHelper.FolderType.Closed));
            imageListLarge.Images.Add(openFolderIconKey, IconHelper.GetFolderIcon(IconHelper.IconSize.Large, IconHelper.FolderType.Open));
            imageListLarge.Images.Add(closedFolderIconKey, IconHelper.GetFolderIcon(IconHelper.IconSize.Large, IconHelper.FolderType.Closed));
            defaultIconSmall = IconHelper.GetSysIcon(0, IconHelper.IconSize.Small);
            defaultIconLarge = IconHelper.GetSysIcon(0, IconHelper.IconSize.Large);
        }

        private void LoadFileIcon(string extension)
        {
            if (!imageListSmall.Images.ContainsKey(extension))
            {
                Icon small = IconHelper.GetExtensionIcon(extension, IconHelper.IconSize.Small);
                if (small != null)
                    imageListSmall.Images.Add(extension, small);
                else
                    imageListSmall.Images.Add(extension, defaultIconSmall);
            }
            if (!imageListLarge.Images.ContainsKey(extension))
            {
                Icon large = IconHelper.GetExtensionIcon(extension, IconHelper.IconSize.Large);
                if (large != null)
                    imageListLarge.Images.Add(extension, defaultIconLarge);
            }
        }
        #endregion

        private void listView_DoubleClick(object sender, EventArgs e)
        {
            if (listView.SelectedItems.Count == 1)
            {
                object tag = listView.SelectedItems[0].Tag;
                if (tag is DirectoryInfo)
                {
                    DirectoryInfo directory = (DirectoryInfo)listView.SelectedItems[0].Tag;
                    LoadDirectory(directory);
                }
                else if (tag is FileInfo)
                {
                    // TODO: Doe iets
                }
            }
        }

        private void treeView_AfterSelect(object sender, TreeViewEventArgs e)
        {
            DirectoryInfo info = (DirectoryInfo)e.Node.Tag;
            LoadDirectory(info);
        }

        private void listView_SelectedIndexChanged(object sender, EventArgs e)
        {
            updateListToolStrip();
        }

        private void setView(object sender, EventArgs e)
        {
            ToolStripItem item = (ToolStripItem)sender;
            string viewMode = (string) item.Tag;
            View view = (View) Enum.Parse(typeof(View), viewMode);
            listView.View = view;
            viewToolStripDropDownButton.Image = item.Image;
        }

        private void parentFolderToolStripButton_Click(object sender, EventArgs e)
        {
            TreeNode[] nodes = treeView.Nodes.Find(currentDirectory.Path, true);
            Debug.Assert(nodes.Length == 1, "Current node could not be found");
            TreeNode node = nodes[0];
            TreeNode parent = node.Parent;
            DirectoryInfo parentDir = parent.Tag as DirectoryInfo;
            LoadDirectory(parentDir);
        }

        private const string newFolderKey = "$$__NEWFOLDER__$$";
        private void createFolderToolStripButton_Click(object sender, EventArgs e)
        {
            ListViewItem newItem = listView.Items.Add(newFolderKey, "New Folder", closedFolderIconKey);
            newItem.Tag = newFolderKey;
            newItem.BeginEdit();
        }

        private void listView_AfterLabelEdit(object sender, LabelEditEventArgs e)
        {
            ListViewItem lvi = listView.Items[e.Item];
            if (lvi.Tag == newFolderKey)
            {
                // create folder
                currentDirectory.CreateFolder(e.Label);
                lvi.Tag = null;
            }
            else if (lvi.Tag is DirectoryInfo)
            {
                DirectoryInfo directory = (DirectoryInfo) lvi.Tag;
                directory.Name = e.Label;
            }
            else if (lvi.Tag is FileInfo)
            {
                // rename file
                FileInfo file = (FileInfo)lvi.Tag;
                file.Name = e.Label;
            }
            ReloadDirectory();
        }

        private void downloadToolStripButton_Click(object sender, EventArgs e)
        {
            List<IRemoteLocation> files = new List<IRemoteLocation>();
            foreach(ListViewItem lvi in listView.SelectedItems)
            {
                IRemoteLocation file = (IRemoteLocation) lvi.Tag;
                files.Add(file);
            }

            string targetName = (files.Count > 1) ? "documents.zip" : files[0].Name;
            string ext = Path.GetExtension(targetName);
            saveFileDialog.Filter = ext+"-files (*"+ext+")|*"+ext+"|All Files|*.*";
            saveFileDialog.FileName = targetName;
            DialogResult result = saveFileDialog.ShowDialog(this);
            if (result == DialogResult.OK)
            {
                DownloadTask task = new DownloadTask(files.ToArray(), saveFileDialog.FileName);
                service.TaskQueue.Add(task);
            }
        }

        private void uploadToolStripButton_Click(object sender, EventArgs e)
        {
            DialogResult result = openFileDialog.ShowDialog();
            if (result == DialogResult.OK)
            {
                foreach(string file in openFileDialog.FileNames)
                {
                    UploadTask task = new UploadTask(file, currentDirectory);
                    service.TaskQueue.Add(task);
                }
            }
        }

        private void extractToolStripButton_Click(object sender, EventArgs e)
        {
            foreach(ListViewItem lvi in listView.SelectedItems)
            {
                FileInfo file = (FileInfo) lvi.Tag;
                ExtractTask task = new ExtractTask(file, currentDirectory, true, true, "");
                service.TaskQueue.Add(task);
            }
        }

        private void copyToolStripButton_Click(object sender, EventArgs e)
        {
            SelectRemoteFolderDialog dialog = new SelectRemoteFolderDialog(service);
            if (dialog.ShowDialog(this.ParentForm) == DialogResult.OK)
            {
                foreach (ListViewItem lvi in listView.SelectedItems)
                {
                    IRemoteLocation fileOrFolder = (IRemoteLocation)lvi.Tag;
                    CopyTask task = new CopyTask(fileOrFolder, dialog.SelectedPath, dialog.Overwrite);
                    service.TaskQueue.Add(task);
                }
            }
        }

        private void moveToolStripButton_Click(object sender, EventArgs e)
        {
            SelectRemoteFolderDialog dialog = new SelectRemoteFolderDialog(service);
            if (dialog.ShowDialog(this.ParentForm) == DialogResult.OK)
            {
                foreach (ListViewItem lvi in listView.SelectedItems)
                {
                    IRemoteLocation fileOrFolder = (IRemoteLocation) lvi.Tag;
                    MoveTask task = new MoveTask(fileOrFolder, dialog.SelectedPath, dialog.Overwrite);
                    service.TaskQueue.Add(task);
                }
            }
        }

        private void deleteToolStripButton_Click(object sender, EventArgs e)
        {
            DialogResult result = MessageBox.Show("Are you sure you wish to delete the selected file(s)?",
                                                  "Delete Files?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if (result == DialogResult.Yes)
            {
                foreach (ListViewItem lvi in listView.SelectedItems)
                {
                    IRemoteLocation fileOrFolder = (IRemoteLocation)lvi.Tag;
                    DeleteTask task = new DeleteTask(fileOrFolder, currentDirectory);
                    service.TaskQueue.Add(task);
                }
            }
        }

        private void renameToolStripButton_Click(object sender, EventArgs e)
        {
            listView.SelectedItems[0].BeginEdit();
        }

        private void propertiesToolStripButton_Click(object sender, EventArgs e)
        {

        }

        private void refreshTreeToolStripButton_Click(object sender, EventArgs e)
        {
            LoadRoot();
        }

        private void refreshListToolStripButton_Click(object sender, EventArgs e)
        {
            ReloadDirectory();
        }
    }
}
